<script setup>
import { ref } from 'vue';
// 卡片的宽高，用于计算偏移量
const CARD_WIDTH = 70;
const CARD_HEIGHT = 70;
// 卡片有几种，种类越多，难度越大
const CARD_KIND = 10;
const CARD_KIND_GROUP_COUNT = 4
// 随机移除多少个数据
const RANDOM_REMOVE_COUNT = 30;
// 最终卡片的总数(因为是 3个 一消除，3 * 所以卡片种类 * 一共有多少组，就是总数)
const CARD_TOTAL = 3 * CARD_KIND * CARD_KIND_GROUP_COUNT + RANDOM_REMOVE_COUNT;
// 临时的卡片的总数（多生成一些卡片，然后才可以随机消除一些）
const CARD_TOTAL_TEMP = CARD_TOTAL + RANDOM_REMOVE_COUNT;

// 可操作的卡片
const cardInfos = ref([])
// 持有的卡片
const holdCardInfos = ref([])
// 游戏是否结束
let isGameOver = false;
// 随机生成的卡片内容
const cardContents = [];
/**
 * 随机生成卡片内容
 */
function initRandomContent() {
  let cardKind = 0;
  for (let index = 0; index < CARD_TOTAL_TEMP; index++) {
    if (cardKind == CARD_KIND)
      cardKind = 0;
    cardContents.push(cardKind)
    cardKind++;
  }
  // 打乱顺序
  cardContents.sort(function () { return 0.5 - Math.random() })
  console.log('random cardContents', cardContents)
}
/**
 * 初始化，生成卡片UI
 */
function initCardInfos() {
  initRandomContent();

  // 这里生成的卡片数量，其实是与最初生成的 cardContents 数量不符的，但是，，，懒得搞了，意思意思得了
  const offsetX = CARD_WIDTH / 2;
  const offsetY = CARD_HEIGHT / 2;
  initOneLevelCardInfos(6, 6, 1);
  initOneLevelCardInfos(5, 5, 2, offsetX * 1, offsetY * 1);
  initOneLevelCardInfos(4, 4, 3, offsetX * 2, offsetY * 2);
  initOneLevelCardInfos(3, 3, 4, offsetX * 3, offsetY * 3);

  randomRemoveCard();
  findAndChangeBottom();
}
/**
 * 生成某一层的卡片们
 * @param {行} row 
 * @param {列} column 
 * @param {层数} level 
 * @param {X 偏移量} offsetX 
 * @param {Y 偏移量} offsetY 
 */
function initOneLevelCardInfos(row, column, level, offsetX = 0, offsetY = 0) {
  for (let rowIndex = 0; rowIndex < row; rowIndex++) {
    for (let columnIndex = 0; columnIndex < column; columnIndex++) {
      if (cardInfos.value.length === CARD_TOTAL_TEMP)
        return
      const x = CARD_WIDTH * rowIndex + offsetX
      const y = CARD_HEIGHT * columnIndex + offsetY
      cardInfos.value.push({
        id: rowIndex + "-" + columnIndex + "-" + level,
        x, y,
        translateStyle: `transform: translate(${x}px, ${y}px);`,
        level,
        isBottom: false,
        cardClass: ["card"],
        content: cardContents.pop()
      })
    }
  }
}

/**
 * 随机移除一些卡片
 */
function randomRemoveCard() {
  for (let index = 0; index < RANDOM_REMOVE_COUNT; index++) {
    const random = Math.floor(Math.random() * cardInfos.value.length);
    console.log('random', random)
    cardInfos.value.splice(random, 1)
  }
}
/**
 * 刷新卡片的样式（白色可点击、灰色不可点击）
 */
function findAndChangeBottom() {
  console.log('cardInfos.value.legnth', cardInfos.value.length)
  cardInfos.value.forEach(aimCard => {
    const coverCardInfo = cardInfos.value.find(item => isCovered(aimCard, item))
    if (coverCardInfo) setCardBottom(aimCard)
    else setCardNormal(aimCard)
  });
}
/**
 * 判断是否被覆盖了
 * @param {*} bottomCard 
 * @param {*} topCard 
 */
function isCovered(bottomCard, topCard) {
  if (bottomCard.level >= topCard.level)
    return false;
  const isXFit = topCard.x - CARD_WIDTH / 2 === bottomCard.x || topCard.x + CARD_WIDTH / 2 === bottomCard.x
  const isYFit = topCard.y - CARD_HEIGHT / 2 === bottomCard.y || topCard.y + CARD_HEIGHT / 2 === bottomCard.y
  return isXFit && isYFit
}
/**
 * 如果被覆盖了，则设置为灰色不可点击
 * @param {*} card 
 */
function setCardBottom(card) {
  card.isBottom = true;
  card.cardClass = ["card card-bottom"];
}
/**
 * 如果没有被覆盖，则设置为白色可点击
 * @param {*} card 
 */
function setCardNormal(card) {
  card.isBottom = false;
  card.cardClass = ["card"];
}

initCardInfos();

function OnCardClick(id) {
  if (isGameOver) {
    alert("game over, please F5")
    return;
  }
  console.log('cardClick, id:', id)
  const index = cardInfos.value.findIndex(item => item.id === id)
  if (index < 0) {
    console.error("click a unknown card:", id)
    return;
  }
  // 底层的不能点击
  if (cardInfos.value[index].isBottom) {
    return;
  }
  // 将卡片加入到手卡中
  holdCardInfos.value.push({ ...cardInfos.value[index] })
  // 移除卡片
  cardInfos.value.splice(index, 1)
  dealHoldCards()
  if (isGameOver) return;
  if (isGameSuccess())
    return;
  findAndChangeBottom();
}
/**
 * 处理手牌；判断游戏失败
 */
function dealHoldCards() {
  if (holdCardInfos.value.length < 3)
    return;
  // 消除三个相同的卡片，懒得算法优化了，简单粗暴一点
  for (let index = 0; index < CARD_KIND; index++) {
    const result = holdCardInfos.value.filter(item => item.content === index);
    // 有三个相同的，移除它们
    if (result.length === 3) {
      const sameIndex1 = holdCardInfos.value.findIndex(item => item.content === index)
      holdCardInfos.value.splice(sameIndex1, 1)
      const sameIndex2 = holdCardInfos.value.findIndex(item => item.content === index)
      holdCardInfos.value.splice(sameIndex2, 1)
      const sameIndex3 = holdCardInfos.value.findIndex(item => item.content === index)
      holdCardInfos.value.splice(sameIndex3, 1)
    }
  }

  if (holdCardInfos.value.length === 8) {
    isGameOver = true;
    alert("game over, please F5")
    return;
  }
}
/**
 * 判断游戏是否结束
 */
function isGameSuccess() {
  if (cardInfos.value.length === 0) {
    alert("老铁 666")
    return true;
  }
}

</script>

<template>
  <div>
    <span class="title">数了个数</span>
    <div class="hold-cards-layout">
      <div v-for="cardInfo in holdCardInfos" class="hold-card">
        {{cardInfo.content}}
      </div>
    </div>
    <div id="mainLayout" style="margin-top:20px; margin-left:70px;">
      <div v-for="cardInfo in cardInfos" :class="cardInfo.cardClass" @click="OnCardClick(cardInfo.id)"
        :style="cardInfo.translateStyle">
        {{cardInfo.content}}
      </div>
    </div>
  </div>
</template>
<style>
/* 定义变量 */
:root {
  --cardWidth: 70px;
  --cardHeight: 70px;
  --cardFontSize: 35px;
}

body {
  background-color: lightgreen;
  margin: 0 !important;
}

.title {
  color: rgb(93, 90, 90);
  font-size: 48px;
  margin: 0 auto;
  text-align: center;
  height: 100vh;
  margin-left: 196px;
}

.hold-cards-layout {
  display: flex;
  flex-direction: row;
  border: 1px solid darkorange;
  align-items: center;
  height: calc(var(--cardHeight) + 20px);
  width: calc(var(--cardWidth) * 8 + 30px);
  padding-bottom: 10px;
  padding-left: 14px;
}

.hold-card {
  width: var(--cardWidth);
  height: var(--cardHeight);
  border-radius: 4px;
  background-color: white;
  color: black;
  font-size: var(--cardFontSize);
  box-shadow: 0 8px 0 green;
  text-align: center;
  line-height: var(--cardHeight);
  border: 1px solid lightgreen;
  cursor: default;
}

.card {
  width: var(--cardWidth);
  height: var(--cardHeight);
  position: absolute;
  border-radius: 4px;
  background-color: white;
  color: black;
  font-size: var(--cardFontSize);
  box-shadow: 0 8px 0 green;
  text-align: center;
  line-height: var(--cardHeight);
  border: 1px solid lightgreen;
  cursor: default;
}

.card-bottom {
  background-color: white;
}

.card.card-bottom::after {
  content: "";
  border-radius: 4px;
  top: 0;
  left: 0;
  position: absolute;
  width: 100%;
  height: 100%;
  opacity: 0.8;
  background: gray;
}
</style>
